package com.pointi.emoEngine;

class var_index
{
	double var ;
	int index ;
}

class twomax
{
	double [] var = new double [2] ;
	int [] index = new int [2] ;
	int arr_num ;
}

public class DSP_Pitch
{
	DSP_Pitch() {
	}
	//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
	public double round(double x)
	{
		if (x >= 0) 
		{
			if ((x - (int)x) >= 0.5)	x = (int)x + 1 ;
			else							x = (int)x ;
		}
		else 
		{		
			if ((x - (int)x) > -0.5)	x = (int)x ;
			else							x = (int)x-1 ;
		}
		return x ;
	}
	//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
	public var_index MAX_1d(double [] x, int var_num)
	{
		int m ;
		var_index max = new var_index() ; // 2012-08-02 //
		max.var = -1000000000 ;

		for (m = 0 ; m < var_num ; m++)
		{
			if (max.var < x[m])
			{
				max.var = x[m] ;
				max.index = m ;
			}
		}
		return max ;
	}
	//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
	public double GetPitch(double [] spectrum)
	{	
		//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
		int [] interp1_k = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 13, 14, 14, 15, 16, 17, 18 } ; // 59��
		double [] interp1_s =
			{
				0.000000000000, 0.074000581444, 0.148001162888, 0.222001744331, 0.296002325775, 0.370002907219, 0.444003488663, 0.518004070106, 0.592004651550, 0.666005232994, 0.740005814438, 0.814006395882, 0.888006977325, 0.962007558769, 0.061556322274, 0.188061151819, 0.314565981364, 0.441070810909, 0.567575640453, 0.694080469998,
				0.820585299543, 0.947090129087, 0.103726268390, 0.282024811467, 0.460323354544, 0.638621897621, 0.816920440698, 0.995218983775, 0.223702999426, 0.453569800799, 0.683436602171, 0.913303403544, 0.175226169243, 0.456560397019, 0.737894624796, 0.022742905449, 0.355490671758, 0.688238438067, 0.024226794973, 0.408355900342,
				0.792485005711, 0.200228564991, 0.635718226993, 0.079603647306, 0.566439669960, 0.058893545865, 0.597065800842, 0.148136529526, 0.737637536890, 0.355619843822, 0.996443922347, 0.688301876588, 0.408650603022, 0.162606785110, 0.957377001153, 0.800705515697, 0.686008218430, 0.616751174016, 0.596025185680
			} ; // 59

		int [] startpos = { 55, 48, 42, 38, 34, 31, 28, 26, 24, 22, 21, 19, 18, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 5, 4, 3, 3, 2, 1 } ; // 31��
		int [] endpos = { 113, 106, 100, 96, 92, 89, 86, 84, 82, 80, 79, 77, 76, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 63, 62, 61, 61, 60, 59 } ; // 31�� 

		double [] newfre =
			{
				31.250000000000, 32.894736842105, 34.626038781163, 36.448461874909, 38.366801973588, 40.386107340619, 42.511691937494, 44.749149407888, 47.104367797777, 49.583545050292, 52.193205316097, 54.940216122207, 57.831806444428, 60.875585730977, 64.079563927344, 67.452172555099, 71.002286900104, 74.739249368531, 78.672894072138, 82.813572707514,
				87.172181797383, 91.760191365666, 96.589675121754, 101.673342233425, 107.024570772026, 112.657442917922, 118.586782018865, 124.828191598806, 131.398096419795, 138.313785705048, 145.593458636892, 153.256272249360, 161.322391841432, 169.813044043613, 178.750572677487, 188.158497555249, 198.061576373947, 208.485869867312, 219.458810386644, 231.009274091204,
				243.167656938110, 255.965954671695, 269.437847022836, 283.618786339828, 298.546090884029, 314.259043035820, 330.798992669284, 348.209465967667, 366.536279965965, 385.827663122069, 406.134382233757, 427.509876035533, 450.010395826877, 473.695153501976, 498.626477370500, 524.869976179474, 552.494711767867, 581.573380808281, 612.182506113980
			} ; // 59
		//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
		int m, n ;
		double [] amplitude = new double [20] ;	
		double interp_min = 10000.0 ;
		double [] log_spectrum = new double [59] ;
		//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
		int len_spectrum = 59 ;
		int shift_units = 68 ;
		int totallen = shift_units + len_spectrum ;
		int N = 32 ;
		double [][] shshift = new double [32][127] ;
		double [] shsodd = new double [59] ;
		shsodd[0] = 0.0 ;
		double [] shseven = new double [59] ;
		shseven[0] = 0.0 ;
		double [] difference = new double [59] ;
		//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
		int lowerbound = 5 ;
		int upperbound = 38 ;
		int harmonics = 2 ;
		int maxf0 = 400 ;
		int peak_index ;
		int CHECK_VOICING = 0 ;		
		double [] tmp ;
		double min_bin = 0.0740 ;
		double LIMIT = 0.0625 ;
		double log2N, log2P ;
		double startposition, endposition ;
		double min_tmp ;
		double [] tmp_diff ;
		double SHR, SHR_Threshold = 0.1 ;
		double cur_cand1, cur_cand2, curf0 = 0.0 ;
		var_index max_mag ;
		var_index max_mag1 ;
		twomax two_max ;
		//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
		for (m = 1 ; m <= 20 ; m++) { amplitude[m-1] = spectrum[m] ; }	

		for (m = 0 ; m < len_spectrum ; m++)
		{ 		
			log_spectrum[m] = amplitude[interp1_k[m]] + interp1_s[m] * (amplitude[interp1_k[m]+1] - amplitude[interp1_k[m]]) ;
			if (interp_min > log_spectrum[m]) { interp_min = log_spectrum[m] ; }		
		}	
		for (m = 0 ; m < len_spectrum ; m++) { log_spectrum[m] = log_spectrum[m] - interp_min ; }
		//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
		for (m = 0 ; m < N ; m++)
		{
			for (n = 0 ; n < totallen ; n++)
			{
				shshift[m][n] = 0 ;

				if (m == 0) { if ((shift_units <= n) && (n < totallen)) { shshift[m][n] = log_spectrum[n - shift_units] ; } }
				else { if ((startpos[m-1] <= n) && (n <= endpos[m-1])) { shshift[m][n-1] = log_spectrum[n - startpos[m-1]] ; } }
			}
			for (n=shift_units ; n<totallen ; n++)
			{
				if (m%2 == 1) { shseven[n - shift_units] += shshift[m][n] ; }
				else { shsodd[n - shift_units] += shshift[m][n] ; }
			}
		}
		for (m = 0 ; m < len_spectrum ; m++) { difference[m] = shseven[m] - shsodd[m] ; }
		//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
		tmp = new double [(upperbound - lowerbound +1)] ;
		for (m=lowerbound ; m <= upperbound ; m++) { tmp[m-lowerbound] = difference[m-1] ; }
		max_mag = MAX_1d(tmp, upperbound - lowerbound + 1) ;
		max_mag.index = max_mag.index + lowerbound - 1 ;
		if (max_mag.var <= 0.0)		
		{
			peak_index = -1 ; 
			curf0 = 0.0 ;
			two_max = new twomax() ;
		}
		else
		{
			tmp = null ;
			log2N = Math.log(harmonics-LIMIT) / Math.log(2.0) ;
			log2P = Math.log(harmonics+LIMIT) / Math.log(2.0) ;
			startposition = (int) (max_mag.index + round(log2N / min_bin)) ;
			if (len_spectrum < upperbound)  { min_tmp = len_spectrum ; }
			else { min_tmp = upperbound ; }
			two_max = new twomax() ;
			two_max.var[0] = max_mag.var ;
			two_max.index[0] = max_mag.index ;
			two_max.arr_num = 1 ;
			if (startposition <= min_tmp)
			{
				endposition = max_mag.index + round(log2P / min_bin) ;
				if (endposition > min_tmp) { endposition = min_tmp ; }
				tmp_diff = new double [(int)(endposition - startposition +1)] ;
				for (m=(int)startposition ; m<=(int)endposition ; m++) { tmp_diff[m - (int)startposition] = difference[m] ; }		
				max_mag1 = MAX_1d(tmp_diff, (int)(endposition - startposition +1)) ;
				if (max_mag1.var > 0)
				{
					max_mag1.index = (int)(max_mag1.index + startposition-1) ;
					two_max.var[0] = max_mag.var ;
					two_max.var[1] = max_mag1.var ;
					two_max.index[0] = max_mag.index ;
					two_max.index[1] = max_mag1.index ;
					two_max.arr_num = 2 ;
				}
			}
			tmp_diff = null ;
			if (two_max.arr_num == 1)		// NumPitchCandidates of MATLAB
			{
				if (two_max.var[0] <= 0)		// this must be an unvoiced frame
				{
					peak_index = -1 ; 
					curf0 = 0.0 ;
				}
				peak_index = two_max.index[0] ;
				SHR = 0 ;
			}
			else
			{
				SHR = (two_max.var[0] - two_max.var[1]) / (two_max.var[0] + two_max.var[1]) ;
				if (SHR <= SHR_Threshold) 
				{
					peak_index = two_max.index[1] ;
				}
				else
				{
					peak_index = two_max.index[0] ;
				}		
			}
		}
		//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
		if (peak_index == -1)
		{
			if (CHECK_VOICING == 1)
			{
				curf0 = 0 ;
				cur_cand1 = 0 ;
				cur_cand2 = 0 ;
			}
		}
		else
		{
			curf0 = newfre[peak_index] * 2 ; 
			if (curf0 > maxf0) curf0 = curf0 / 2 ;
			if (two_max.arr_num == 1)
			{
				cur_cand1 = 0 ;
				cur_cand2 = newfre[two_max.index[0]] * 2 ;
			}
			else
			{
				cur_cand1 = newfre[two_max.index[0]] * 2 ;
				cur_cand2 = newfre[two_max.index[1]] * 2 ;
			}
			if (cur_cand1 > maxf0)	cur_cand1 = cur_cand1 / 2 ;
			if (cur_cand2 > maxf0)	cur_cand2 = cur_cand2 / 2 ;		
		}	
		return curf0 ;
		//-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
	}
}